/*
 * Copyright (C) 2010 Fred Barrie This program is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.aergia.vinny.engine;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author fred
 */
public class VinnyConfiguration {

	private class PersistenceUnitConfiguration {

		String databaseName;
		int locationId;
		String password;
		String persistenceUnit;
		public int portNumber;
		String serverName;
		String userName;
		int workstationId;

		public PersistenceUnitConfiguration() {
			this.locationId = VinnyConfiguration.DEFAULT_LOCATION_ID;
			this.databaseName = VinnyConfiguration.DEFAULT_DATABASE_NAME;
			this.serverName = VinnyConfiguration.DEFAULT_SERVER_NAME;
			this.persistenceUnit = VinnyConfiguration.DEFAULT_PERSISTENCE_UNIT;
			this.password = VinnyConfiguration.DEFAULT_PASSWORD;
			this.userName = VinnyConfiguration.DEFAULT_USER_NAME;
			this.workstationId = VinnyConfiguration.DEFAULT_WORKSTATION_ID;
			this.portNumber = VinnyConfiguration.DEFAULT_PORT_NUMBER;
		}
	}

	private static final String DATABASE_NAME = "databaseName";
	private static final String DEFAULT_DATABASE_NAME = "trackin";
	private static final String DEFAULT_DATABASE_URL = "jdbc:mysql://localhost:3306/aergiao1_vinny";
	private static final int DEFAULT_LOCATION_ID = 0;
	private static final String DEFAULT_PASSWORD = "7t%X5^z@";
	private static final String DEFAULT_PERSISTENCE_UNIT = "vinny";
	private static final int DEFAULT_PORT_NUMBER = 3306;
	private static final String DEFAULT_SERVER_NAME = "localhost";
	private static final String DEFAULT_USER_NAME = "trackin";
	private static final int DEFAULT_WORKSTATION_ID = 0;
	private static final String ID = "id";
	private static final String LOCATION = "location";
	private static final String PASSWORD = "password";
	private static final String PERSISTENCE_UNIT = "persistenceUnit";
	private static final String PORT_NUMBER = "portNumber";
	private static final String SERVER_NAME = "serverName";
	private static final String USER_NAME = "userName";
	private static final String WORKSTATION_ID = "workstationId";

	Map<String, PersistenceUnitConfiguration> persistenceUnits;

	public VinnyConfiguration() {
		this.persistenceUnits = new HashMap<String, PersistenceUnitConfiguration>();
		final PersistenceUnitConfiguration cfg = new PersistenceUnitConfiguration();
		this.persistenceUnits.put(cfg.persistenceUnit, cfg);
	}

	public void addPersistenceUnit(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = new PersistenceUnitConfiguration();
		cfg.persistenceUnit = persistenceUnit;
		this.persistenceUnits.put(persistenceUnit, cfg);
	}

	public String getDatabaseName(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.databaseName : VinnyConfiguration.DEFAULT_DATABASE_NAME;
	}

	public String getDatabaseUrl(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? ("jdbc:mysql://" + this.getServerName(persistenceUnit) + ":" + this.getPortNumber(persistenceUnit) + "/" + this
				.getDatabaseName(persistenceUnit)) : VinnyConfiguration.DEFAULT_DATABASE_URL;
	}

	public int getLocationId(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.locationId : 0;
	}

	public String[] getPersistenceUnitNames() {
		return this.persistenceUnits.keySet().toArray(new String[0]);
	}

	public int getPortNumber(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.portNumber : 0;
	}

	public String getServerName(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.serverName : VinnyConfiguration.DEFAULT_SERVER_NAME;
	}

	public String getUserName(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.userName : VinnyConfiguration.DEFAULT_USER_NAME;
	}

	public String getUserPassword(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.password : VinnyConfiguration.DEFAULT_PASSWORD;
	}

	public int getWorkstationId(final String persistenceUnit) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		return cfg != null ? cfg.workstationId : 0;
	}

	public void loadConfigurationFile(final String configurationFileName) {
		try {
			final InputStream input = new FileInputStream(configurationFileName);
			final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			final Document document = builder.parse(input);
			final Element element = document.getDocumentElement();
			final NodeList nodes = element.getChildNodes();
			for (int i = 0; i < nodes.getLength(); i++) {
				final Node node = nodes.item(i);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					if (node.getNodeName().equals(VinnyConfiguration.PERSISTENCE_UNIT)) {
						this.parsePersistenceUnit((Element) node);

					}
				}
			}
		} catch (final Exception e) {
			final PersistenceUnitConfiguration cfg = new PersistenceUnitConfiguration();
			cfg.locationId = VinnyConfiguration.DEFAULT_LOCATION_ID;
			cfg.databaseName = VinnyConfiguration.DEFAULT_DATABASE_NAME;
			cfg.serverName = VinnyConfiguration.DEFAULT_SERVER_NAME;
			cfg.persistenceUnit = VinnyConfiguration.DEFAULT_PERSISTENCE_UNIT;
			cfg.password = VinnyConfiguration.DEFAULT_PASSWORD;
			cfg.userName = VinnyConfiguration.DEFAULT_USER_NAME;
			cfg.workstationId = VinnyConfiguration.DEFAULT_WORKSTATION_ID;
			cfg.portNumber = VinnyConfiguration.DEFAULT_PORT_NUMBER;
			this.persistenceUnits.put(cfg.persistenceUnit, cfg);
		}
	}

	private void parsePersistenceUnit(final Element root) {
		final PersistenceUnitConfiguration cfg = new PersistenceUnitConfiguration();
		cfg.persistenceUnit = root.getAttribute(VinnyConfiguration.PERSISTENCE_UNIT);
		final NodeList nodes = root.getChildNodes();
		for (int i = 0; i < nodes.getLength(); i++) {
			final Node node = nodes.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				if (node.getNodeName().equals(VinnyConfiguration.LOCATION)) {
					final Element element = (Element) node;
					try {
						final String idText = element.getAttribute(VinnyConfiguration.ID);
						cfg.locationId = Integer.parseInt(idText);
					} catch (final NumberFormatException nfe) {
						cfg.locationId = 0;
					}
					try {
						final String idText = element.getAttribute(VinnyConfiguration.WORKSTATION_ID);
						cfg.workstationId = Integer.parseInt(idText);
					} catch (final NumberFormatException nfe) {
						cfg.workstationId = 0;
					}

					try {
						final String idText = element.getAttribute(VinnyConfiguration.PORT_NUMBER);
						cfg.portNumber = Integer.parseInt(idText);
					} catch (final NumberFormatException nfe) {
						cfg.portNumber = 3306;
					}
					cfg.databaseName = element.getAttribute(VinnyConfiguration.DATABASE_NAME);
					cfg.password = element.getAttribute(VinnyConfiguration.PASSWORD);
					cfg.serverName = element.getAttribute(VinnyConfiguration.SERVER_NAME);
					cfg.userName = element.getAttribute(VinnyConfiguration.USER_NAME);
					cfg.workstationId = VinnyConfiguration.DEFAULT_WORKSTATION_ID;
				}
			}
		}
		this.persistenceUnits.put(cfg.persistenceUnit, cfg);
	}

	public void saveConfigurationFile(final String configurationFileName) {

		try {
			final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			final Document document = builder.newDocument();
			final Element root = document.createElement("configuration");

			for (final PersistenceUnitConfiguration persistenceUnitCfg : this.persistenceUnits.values()) {

				final Element persistenceUnit = document.createElement(VinnyConfiguration.PERSISTENCE_UNIT);
				persistenceUnit.setAttribute(VinnyConfiguration.PERSISTENCE_UNIT, persistenceUnitCfg.persistenceUnit);

				final Element location = document.createElement(VinnyConfiguration.LOCATION);
				location.setAttribute(VinnyConfiguration.ID, Integer.toString(persistenceUnitCfg.locationId));
				location.setAttribute(VinnyConfiguration.WORKSTATION_ID, Integer.toString(persistenceUnitCfg.workstationId));
				location.setAttribute(VinnyConfiguration.DATABASE_NAME, persistenceUnitCfg.databaseName);
				location.setAttribute(VinnyConfiguration.PASSWORD, persistenceUnitCfg.password);
				location.setAttribute(VinnyConfiguration.SERVER_NAME, persistenceUnitCfg.serverName);
				location.setAttribute(VinnyConfiguration.USER_NAME, persistenceUnitCfg.userName);
				location.setAttribute(VinnyConfiguration.PORT_NUMBER, Integer.toString(persistenceUnitCfg.portNumber));
				persistenceUnit.appendChild(location);
				root.appendChild(persistenceUnit);
			}

			document.appendChild(root);

			final Transformer transformer = TransformerFactory.newInstance().newTransformer();
			final DOMSource source = new DOMSource(document);
			final File output = new File(configurationFileName);
			output.getParentFile().mkdirs();
			final StreamResult result = new StreamResult(new File(configurationFileName));
			transformer.transform(source, result);

		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	public void setDatabaseName(final String persistenceUnit, final String name) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		if (cfg != null) {
			cfg.databaseName = name;
		}
	}

	public void setLocationId(final String persistenceUnit, final int id) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		if (cfg != null) {
			cfg.locationId = id;
		}
	}

	public void setPassword(final String persistenceUnit, final String password) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		cfg.password = password;
	}

	public void setPortNumber(final String persistenceUnit, final int value) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		cfg.portNumber = value;
	}

	public void setServerName(final String persistenceUnit, final String name) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		cfg.serverName = name;
	}

	public void setUserName(final String persistenceUnit, final String name) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		cfg.userName = name;
	}

	public void setWorkstationId(final String persistenceUnit, final int workstationId) {
		final PersistenceUnitConfiguration cfg = this.persistenceUnits.get(persistenceUnit);
		cfg.workstationId = workstationId;
	}
}
